﻿using HSGD.AuthHelper;
using HSGD.Common;
using HSGD.Common.AppConfig;
using HSGD.Extensions.Authorizations.Policys;
using HSGD.Services;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace HSGD.Extensions;

/// <summary>
/// JWT权限 认证服务
/// </summary>
public static class Authentication_JWTSetup {
    private static readonly string[] groupSidAllowedValues = ["HSGDeMS", "eIS", "EisOnline"];

    public static void AddAuthenticationJWTSetup(this IServiceCollection services) {
        if (services == null) throw new ArgumentNullException(nameof(services));
        var Issuer = AppSettings.app(["Audience", "Issuer"]);
        var Audience = AppSettings.app(["Audience", "Audience"]);

        services.AddAuthorization(options => {
            options.AddPolicy("client", policy => policy.RequireRole("admin").Build());
            options.AddPolicy("Admin", policy => policy.RequireRole("admin").Build());
            options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("admin", "system"));
            options.AddPolicy("A_S_O", policy => policy.RequireRole("Admin", "System", "Others"));
            options.AddPolicy("Policy_HSGDeMS", policy => policy.RequireClaim(ClaimTypes.GroupSid, groupSidAllowedValues));

            options.AddPolicy(Permissions.Name, policy => policy.Requirements.Add(new CustomizePermissionRequirement()));
        });

        services.AddScoped<IAuthorizationHandler, CustomizePermissionRequirement>();

        // 令牌验证参数
        var tokenValidationParameters = new TokenValidationParameters {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,

            ValidIssuer = Issuer,//发行人
            ValidAudience = Audience,//订阅人
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(AppSecretConfig.Audience_Secret_String)),

            LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken,
                TokenValidationParameters validationParameters) => {
                    var dt = notBefore <= DateTime.Now && expires >= DateTime.UtcNow;
                    Console.WriteLine(dt);
                    return dt;
                },

            //ClockSkew = TimeSpan.FromSeconds(30),
            //RequireExpirationTime = true,
        };

        // 开启Bearer认证
        services.AddAuthentication(o => {
            o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            o.DefaultChallengeScheme = nameof(ApiResponseHandler);
            o.DefaultForbidScheme = nameof(ApiResponseHandler);
            //o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            //o.DefaultChallengeScheme = nameof(ApiResponseHandler);
            //o.DefaultForbidScheme = nameof(ApiResponseHandler);
        })
        //services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        // 添加JwtBearer服务
        .AddJwtBearer(o => {
            o.TokenValidationParameters = tokenValidationParameters;
            o.IncludeErrorDetails = true;

            o.Events = new JwtBearerEvents {
                OnMessageReceived = context => {
                    var accessToken = context.Request.Query["access_token"];

                    // If the request is for our hub...
                    var path = context.HttpContext.Request.Path;
                    if (!string.IsNullOrEmpty(accessToken) &&
                        (path.StartsWithSegments("/api2/chathub"))) {
                        // Read the token out of the query string
                        context.Token = accessToken;
                    }
                    return Task.CompletedTask;
                },
                OnChallenge = context => {
                    context.Response.Headers["Token-Error"] = context.ErrorDescription;
                    return Task.CompletedTask;
                },
                OnAuthenticationFailed = context => {
                    var jwtHandler = new JwtSecurityTokenHandler();
                    var token = context.Request.Headers["Authorization"].ObjToString().Replace("Bearer ", "");

                    if (token.IsNotEmptyOrNull() && jwtHandler.CanReadToken(token)) {
                        var jwtToken = jwtHandler.ReadJwtToken(token);

                        if (jwtToken.Issuer != Issuer) {
                            context.Response.Headers["Token-Error-Iss"] = "issuer is wrong!";
                        }

                        if (jwtToken.Audiences.FirstOrDefault() != Audience) {
                            context.Response.Headers["Token-Error-Aud"] = "Audience is wrong!";
                        }
                    }


                    // 如果过期，则把<是否过期>添加到，返回头信息中
                    //if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) {
                    if (context.Exception.GetType() == typeof(SecurityTokenInvalidLifetimeException)) {
                        context.Response.Headers["Token-Expired"] = "true";
                    }
                    return Task.CompletedTask;
                }
            };
        })
        .AddScheme<AuthenticationSchemeOptions, ApiResponseHandler>(nameof(ApiResponseHandler), o => { });

    }
}
